#!/usr/bin/env python
import os
import datetime
import shutil
import threading
import itertools
import time
import argparse
import logging

class JLinkDownloader:
    def __init__(self):
        self.jlink_exe = "JLink.exe"
        self.script_content = '''
        device STM32F103ZE
        speed 4000
        if SWD
        loadfile app.hex
        r
        q
        '''
        self.script_file = "flash.jlink"

    def download(self):
        """执行JLink下载"""
        try:
            self._create_script_file()
            self._execute_download()
        except Exception as e:
            logging.error(f"JLink下载失败: {str(e)}")
        finally:
            self._cleanup()

    def _create_script_file(self):
        """创建JLink脚本文件"""
        with open(self.script_file, "w") as f:
            f.write(self.script_content)

    def _execute_download(self):
        """执行下载命令"""
        os.system(f"{self.jlink_exe} -CommandFile {self.script_file}")

    def _cleanup(self):
        """清理临时文件"""
        if os.path.exists(self.script_file):
            os.remove(self.script_file)

class BuildManager:
    def __init__(self):
        self.spinning = False
        self.build_log_file = "mdk/build_log.txt"
        self.build_command = 'UV4.exe -j0 -r mdk/app.uvprojx -o build_log.txt'
        self.copy_out_file = 'copy mdk\\output\\app.hex output'
        self.out_file_name = 'app.hex'
        self.checksum_file = "checksum.exe app.hex "
        self.checksum_commands = {
            'ALL': self.checksum_file + 'ALL',
            'CHECKSUM': self.checksum_file + 'CHECKSUM',
            'CRC16': self.checksum_file + 'CRC16',
            'CRC32': self.checksum_file + 'CRC32',
            'SHA256': self.checksum_file + 'SHA256',
            'SHA512': self.checksum_file + 'SHA512',
            'MD5': self.checksum_file + 'MD5',
            'SHA1': self.checksum_file + 'SHA1',
        }
        self._setup_logging()
        self.downloader = JLinkDownloader()

    def _setup_logging(self):
        """初始化日志配置"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('build.log', mode='w', encoding='utf-8'),
                logging.StreamHandler()
            ]
        )

    def rm_output(self):
        """删除output文件夹"""
        name = "output"
        path = "./" + name
        if os.path.exists(path):
            shutil.rmtree(path)

    def spinner(self):
        """显示构建进度动画"""
        start_time = time.time()
        while self.spinning:
            for c in itertools.cycle(['|', '/', '-', '\\']):
                if not self.spinning:
                    break
                print(f'\rBuilding... {c}', end='', flush=True)
                time.sleep(0.1)
                elapsed_time = time.time() - start_time
                print(f'\nElapsed time: {elapsed_time:.2f} seconds', end='', flush=True)
                print('\033[F', end='', flush=True)
        print('\rBuild complete!   \n', end='', flush=True)

    def build(self):
        """编译项目"""
        self.spinning = True
        spinner_thread = threading.Thread(target=self.spinner)
        spinner_thread.start()

        os.system(self.build_command)

        self.spinning = False
        spinner_thread.join()

    def log_file_print(self):
        """输出编译log文件"""
        try:
            with open(self.build_log_file, "r") as f:
                data = f.read()
                logging.info(data)
        except FileNotFoundError:
            logging.error(f"错误：编译日志文件 {self.build_log_file} 未找到，请检查编译是否成功")
        except Exception as e:
            logging.error(f"读取日志文件时发生错误：{str(e)}")

    def copy_hex_file(self):
        """复制输出文件到run目录"""
        if not os.path.exists("output"):
            os.makedirs("output")
        os.system(self.copy_out_file)

    def checksum_hex_file(self):
        """计算hex文件的校验和"""
        cur_dir = os.getcwd()
        os.chdir("output")
        os.system(self.checksum_commands['CRC32'])
        os.chdir(cur_dir)

    def run(self, build=False, download=False):
        """运行构建或下载流程"""
        if not build and not download:
            logging.info("请指定操作参数：")
            logging.info("  -m 执行编译")
            logging.info("  -j 执行JLink下载")
            return

        if build:
            self.build()
            self.log_file_print()
            self.copy_hex_file()
            self.checksum_hex_file()

        if download:
            output_dir = "output"
            if not os.path.exists(output_dir):
                os.makedirs(output_dir, exist_ok=True)
            os.chdir(output_dir)
            self.downloader.download()
            os.chdir("..")

def main():
    parser = argparse.ArgumentParser(description='Build script')
    parser.add_argument('-m', action='store_true', help='执行编译')
    parser.add_argument('-j', action='store_true', help='执行JLink下载')
    args = parser.parse_args()

    start = datetime.datetime.now()

    build_manager = BuildManager()
    build_manager.run(args.m, args.j)

    end = datetime.datetime.now()
    logging.info('运行时间: %s 秒' % (end - start))

if __name__ == "__main__":
    main()